package com.wf.controller;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.lang.Validator;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.wf.constant.MessageConstant;
import com.wf.constant.RedisConstant;
import com.wf.domain.User;
import com.wf.dto.LoginDTO;
import com.wf.exception.ApartmentException;
import com.wf.properties.JwtProperties;
import com.wf.service.EnterpriseInfoService;
import com.wf.service.UserService;
import com.wf.service.impl.JavaMailServiceImpl;
import com.wf.utils.*;
import com.wf.vo.Result;
import com.wf.vo.UserVO;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.HashMap;

/**
 * 用户接口
 */
@RestController
@CrossOrigin
@RequestMapping("/app/user")
@Slf4j
public class UserController {
    @Autowired
    private UserService userService;

    @Autowired
    private WxMaService wxMaService;

    @Autowired
    JwtProperties jwtProperties;

    @Autowired
    RedisUtil redisUtil;

    @Autowired
    AliOssUtil aliOssUtil;

    @Autowired
    SendSmsUtil sendSmsUtil;
    @Autowired
    JavaMailServiceImpl javaMailService;

    @Autowired
    EnterpriseInfoService enterpriseInfoService;

    /**
     * 微信登录
     *
     * @param code 前端授权登录后传来的code
     * @return 授权信息结果
     */
    @ApiOperation("获取微信授权信息")
    @ApiImplicitParam(name = "code", value = "前端授权登录后传来的code", required = true, paramType = "query")
    @GetMapping(value = "/wechatSession/{code}")
    public Result wechatSession(@PathVariable String code) {
        // 获取openId、unionid、session_key
        WxMaJscode2SessionResult sessionInfo;
        String token;
        User user;
        try {
            sessionInfo = wxMaService.getUserService().getSessionInfo(code);
            String openid = sessionInfo.getOpenid();
            String sessionKey = sessionInfo.getSessionKey();
            String unionid = sessionInfo.getUnionid();
            user = userService.loginByWx(openid);
            HashMap<String, Object> map = new HashMap<>();
            map.put("openid", openid);
            map.put("userId", user.getUserId());
            token = JwtUtil.createJWT(jwtProperties.getUserSecretKey(), jwtProperties.getUserTtl(), map);


        } catch (WxErrorException e) {
            throw new RuntimeException(e);
        }
        UserVO userVO = new UserVO();
        userVO.setUserInfo(user);
        userVO.setToken(token);
        return Result.success(userVO);
    }

    /**
     * 发送手机验证码
     *
     * @param phone 用户电话号码
     * @return 操作结果
     */
    @PostMapping("/sendPhoneCode/{phone}")
    public Result sendCode(@PathVariable String phone) {

        if (!Validator.isMobile(phone)) {
            return Result.failure("手机号非法");
        }

        String code = (String) redisUtil.get(RedisConstant.APARTMENT_USER_INFO_BY_PHONE_CODE + phone);
        Object after = redisUtil.get(RedisConstant.APARTMENT_USER_INFO_BY_PHONE_CODE_TIME + phone);
//        boolean isEmail = Validator.isEmail("loolly@gmail.com");

        Result<Object> failure = valideCodeTime(after);
        if (failure != null) return failure;
        if (StrUtil.isNotEmpty(code)) {

             sendSmsUtil.sendCode(phone, code);

            log.info("已有验证码：" + code);
        } else {
            code = RandomUtil.randomNumbers(6);
            log.info("无验证码：" + code);
             sendSmsUtil.sendCode(phone, code);
        }
        redisUtil.set(RedisConstant.APARTMENT_USER_INFO_BY_PHONE_CODE + phone, code, 60 * 5);
        redisUtil.set(RedisConstant.APARTMENT_USER_INFO_BY_PHONE_CODE_TIME + phone, LocalDateTime.now(), 60 * 5);
        return Result.success();
    }

    /**
     * 发送邮箱验证码
     *
     * @param email 用户电话号码
     * @return 操作结果
     */
    @PostMapping("/sendMailCode/{email}")
    public Result sendMailCode(@PathVariable String email) {

        if (!Validator.isEmail(email)) {
            return Result.failure("邮箱非法！");
        }

        String code = (String) redisUtil.get(RedisConstant.APARTMENT_USER_INFO_BY_EMAIL_CODE + email);
        Object after = redisUtil.get(RedisConstant.APARTMENT_USER_INFO_BY_EMAIL_CODE_TIME + email);


        Result<Object> failure = valideCodeTime(after);
        if (failure != null) return failure;
        if (StrUtil.isNotEmpty(code)) {

        javaMailService.sendEmailCode(email, code);

            log.info("已有验证码：" + code);
        } else {
            code = RandomUtil.randomNumbers(6);
            log.info("无验证码：" + code);
          javaMailService.sendEmailCode(email, code);
        }
        redisUtil.set(RedisConstant.APARTMENT_USER_INFO_BY_EMAIL_CODE + email, code, 60 * 5);
        redisUtil.set(RedisConstant.APARTMENT_USER_INFO_BY_EMAIL_CODE_TIME + email, LocalDateTime.now(), 60 * 5);
        return Result.success();
    }

    @Nullable
    private static Result<Object> valideCodeTime(Object after) {
        if (ObjectUtil.isNotEmpty(after)) {
            LocalDateTime parse = LocalDateTimeUtil.parse(
                    String.valueOf(after), "yyyy-MM-dd HH:mm:ss");
            Duration between = LocalDateTimeUtil.between(parse, LocalDateTime.now());
            if (between.toMinutes() < 1) {
                log.info(String.valueOf(between.getSeconds()));
                return Result.failure("验证码已发送，请稍后再试");
            }
        }
        return null;
    }

    /**
     * 登录
     *
     * @param loginDTO 登录数据传输对象
     * @return 登录结果
     */
    @PostMapping("/login")
    public Result login(@RequestBody LoginDTO loginDTO) throws ApartmentException {

        if (Validator.isMobile(loginDTO.getPhone())) {
            String code = (String) redisUtil.get(RedisConstant.APARTMENT_USER_INFO_BY_PHONE_CODE + loginDTO.getPhone());
            return valideCode(loginDTO, code);

        } else if (Validator.isEmail(loginDTO.getEmail())) {
            String code = (String) redisUtil.get(RedisConstant.APARTMENT_USER_INFO_BY_EMAIL_CODE + loginDTO.getEmail());
            return valideCode(loginDTO, code);

        } else {
            return Result.failure("请输入正确的手机号或邮箱");
        }

    }

    @NotNull
    private Result valideCode(@RequestBody LoginDTO loginDTO, String code) throws ApartmentException {
        String token;
        if (code.equals(loginDTO.getCode())) {
            User user = userService.login(loginDTO);
            HashMap<String, Object> map = new HashMap<>();
            map.put("userId", user.getUserId());
            map.put("code", loginDTO.getCode());
            token = JwtUtil.createJWT(jwtProperties.getUserSecretKey(), jwtProperties.getUserTtl(), map);
            UserVO userVO = new UserVO();
            userVO.setUserInfo(user);
            userVO.setToken(token);
            return Result.success(userVO);
        } else {
            throw new ApartmentException(MessageConstant.VERIFICATION_CODE_ERROR);
        }
    }

    /**
     * 更新用户信息
     *
     * @param user 待更新的用户信息
     * @return 操作结果
     */
    @PutMapping("/update")
    public Result update(@RequestBody User user) throws ApartmentException {

        if (StrUtil.isNotEmpty(user.getCode())) {
            boolean flag = userService.updatePhoneOrEmail(user);

            return flag ? Result.success() : Result.failure("更新失败");
        }
        // 判断是否上传了头像
        if (user.getAvatar() != null) {
            MultipartFile multipartFile = BASE64DecodedMultipartFile.base64ToMultipart(user.getAvatar());
            // 生成新的文件名
            String objectName;
            String prefix = "avatar/";
            if (multipartFile != null) {
                objectName =prefix + FileNameUtils.getFileName(multipartFile.getOriginalFilename());
                try {
                    // 调用aliOssUtil的upload方法上传文件，并获取上传后的文件路径
                    String filePath = aliOssUtil.upload(multipartFile.getBytes(), objectName);
                    user.setAvatar(filePath);
                    redisUtil.sSet(RedisConstant.APARTMENT_USED_IMG, objectName);
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }
        userService.update(user, new LambdaQueryWrapper<User>().eq(User::getUserId, user.getUserId()));
        return Result.success();

    }


}